/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package validators.annotations;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
import validators.Validator;
import validators.ValidatorError;

/**
 *Parser for annnotation Validate
 * @author arruda
 */
public class ValidateAnnotationParser {

    public boolean validate(Object instance) throws ValidatorError {
        Class clazz = instance.getClass();
        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            if (field.isAnnotationPresent(Validate.class)) {
                Validate validate = field.getAnnotation(Validate.class);
                Class validatorClass = validate.useValidator();
                Object validator =null;
                Object fieldValue =null;
                Object dependence =null;
                try{
                    validator = validatorClass.cast(validatorClass.newInstance());
                    fieldValue = getFieldValue(instance,field.getName());
                    if(fieldValue == null){
                        if(validate.nullable()){
                            return true;
                        }
                        return false;
                    }
                    System.out.println("fieldValue "+fieldValue);
                    dependence = getFieldValue(instance,validate.fieldDependence()); 
                    if(validator instanceof Validator){
                        if(!validateField(validator, fieldValue, dependence)){
                            return false;
                        }
                    }  
                    
                }catch(IllegalAccessException e){
                    e.printStackTrace();
                    return false;
                }catch(InstantiationException e){
                    e.printStackTrace();
                    return false;
                }catch(IllegalArgumentException e){
                    e.printStackTrace();
                    return false;
                }catch(NoSuchFieldException e){
                    e.printStackTrace();
                    return false;
                }catch(NoSuchMethodException e){
                    e.printStackTrace();
                    return false;
                }catch(InvocationTargetException e){
                    e.printStackTrace();
                    return false;
                }
                
            }
        }
        return true;
    }
    public Object getFieldValue(Object instance, String fieldName) 
            throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException{
        if(fieldName.isEmpty())
            return null;
        String getter_name = "get"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
        Method getter = instance.getClass().getMethod(getter_name,null);
//        Field fieldDependence = instance.getClass().getField(fieldName);

        System.out.println("getter "+getter);
        Class dependenceType = getter.getReturnType();

        System.out.println("dependenceType "+dependenceType);
        Object value = null;
                    
//	Constructor[] ctors = dependenceType.getDeclaredConstructors();
//	Constructor ctor = null;
//	for (int i = 0; i < ctors.length; i++) {
//	    ctor = ctors[i];
//	    if (ctor.getGenericParameterTypes().length == 0)
//		break;
//	}
//        Class []parametersClassForInstace = ctor.getParameterTypes();
//        Object [] nullParametersForInstance = 
//                new Object[parametersClassForInstace.length];
        
        
//        value = ctor.newInstance();
        value = dependenceType.cast(getter.invoke(instance));
//        value = dependenceType.cast(fieldDependence.get(instance));
                 
        return value;
    }
    
    public boolean validateField(Object validator,Object fieldValue, Object dependence) throws ValidatorError{
        
       boolean res=false;  
        try{
            Object []methodArgs = {fieldValue, dependence};
            int numArgs=2;
            if(dependence != null){
                numArgs++;
            }
//            Class []methodArgsClass = new Class[numArgs];
//            methodArgsClass[0] = validator.getClass();
//            methodArgsClass[1] =fieldValue.getClass();
            System.out.println("aaaa"+validator.getClass());
            System.out.println("bbbbb"+fieldValue.getClass());
            Class []methodArgsClass = {
                validator.getClass(),
                fieldValue.getClass()
            };
            Method validateMethod = validator.getClass().getMethod("validate",Object.class,Object.class);//, validator.getClass(),fieldValue.getClass());

            //como pegar os errors?
            try {
                res = (Boolean) validateMethod.invoke(validator, methodArgs);
            } catch (InvocationTargetException ex) {
                ValidatorError error = (ValidatorError) ex.getCause();
                throw error;
            }

        }catch(IllegalAccessException e){          
            e.printStackTrace();
        }catch(NoSuchMethodException e){          
            e.printStackTrace();  
        }
       
       return res;
    }
    
}
